package pro.view.core;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.*;
import java.net.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
import pro.control.core.Driver;
import pro.model.core.*;
import pro.model.data.HighScore;
import pro.resources.*;
import pro.view.adaptor.*;



/**
 * @author  sangwo.y
 */
public class GameView extends JFrame implements Observer {
	
	public static final int COLUMN_X_OFFSET = 15;
	public static final int COLUMN_Y_OFFSET = 150;
	public static final int CARD_WIDTH = 92;
	public static final int CARD_HEIGHT = 133;
	public static final int COLUMN_Y_STEP = 25;
	public static final int ACCEPT_SUPL_Y_SPACE = 25;
	
	public static final int CELL_X_OFFSET = 3;
	public static final int CELL_Y_OFFSET = 25;
	public static final int END_CELL_X_STEP = 110+CELL_X_OFFSET+4*(CARD_WIDTH+CELL_X_OFFSET);
	
//	private List<IHolder> holders;
	
	private Driver driver;
	private Wrapper model;
	
	private DefaultTableModel scoreTableModel;
	private JTable scoreTable;
	private JScrollPane scorePane;
	private JScrollPane rulesPane;
	
	private HighScore scores;
	

	public GameView(Game game) {
		super("FreeCell");
		makeMenu();
		makeFrame();
		initScores();
		initGame(game);
	}
	
	private void makeMenu() {
		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);
			JMenu menu; 
			menu = new JMenu("File");
			menu.setMnemonic(KeyEvent.VK_F);
				JMenuItem menuItem; 
				menuItem = new JMenuItem("New Game", KeyEvent.VK_N);	
				menuItem.addActionListener(new ActionListener() {
						public void actionPerformed(ActionEvent arg0) {
							driver.resetGame();				
						}						
					});
				menu.add(menuItem);
				  
			menu.addSeparator();
				
				menuItem = new JMenuItem("Player Name...", KeyEvent.VK_P);
				menuItem.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						String value = JOptionPane.showInputDialog("Player's Name", model.getPlayer());
						if ((value!=null)&&(value.length()!=0)) 
							model.setPlayer(value);
					}						
				});			
				menu.add(menuItem);
				
				
				menuItem = new JMenuItem("See High Scores...", KeyEvent.VK_H);
				final JFrame window = this;				
				menuItem.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {						
						JOptionPane.showMessageDialog(window, scorePane, 
								"High Scores", JOptionPane.INFORMATION_MESSAGE);					
					}						
				});			
				menu.add(menuItem);
				
				menuItem = new JMenuItem("Re-Sync High Scores", KeyEvent.VK_R);	
				menuItem.setToolTipText("HighScoreServer Up");
				menuItem.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {						
						scores.loadFromServer();					
					}						
				});			
				menu.add(menuItem);
				
				
			menu.addSeparator();
			
				menuItem = new JMenuItem("Exit", KeyEvent.VK_E);
				menuItem.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {						
						scores.addGame(model.getPlayer(), model.getDuration(), model.getScore());
						System.exit(0);
					}						
				});		
				menu.add(menuItem);
				
			menuBar.add(menu);
			
			menu = new JMenu("Help");
			menu.setMnemonic(KeyEvent.VK_H);
			
				menuItem = new JMenuItem("Rules", KeyEvent.VK_R);
			
				//final JFrame window = this;				
				menuItem.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {		
						JOptionPane.showMessageDialog(window, rulesPane, 
								"Rules Of Engagement", JOptionPane.INFORMATION_MESSAGE);					
					}						
				});			
			menu.add(menuItem);
			
			menu.add(menuItem);
			menuBar.add(menu);
	}
	
	private void makeFrame() {
		String[] names = {"Player", "Duration", "Score"};
		scoreTableModel = new DefaultTableModel(names,0);
		scoreTable = new JTable(scoreTableModel);
		scorePane = new JScrollPane(scoreTable);
		scorePane.setPreferredSize(new Dimension(250, 350));

		try {
				
				JEditorPane editor = new JEditorPane();
				editor.setEditable(false);
				rulesPane = new JScrollPane(editor); 
				rulesPane.setPreferredSize(new Dimension(420, 300));
				//System.out.println(ResourceLocator.getInstance().getFileAsInputStream("rulesOfEngagement.html"));
				javax.swing.text.html.HTMLEditorKit kit = new javax.swing.text.html.HTMLEditorKit();
				editor.setEditorKit(kit);
				javax.swing.text.html.HTMLDocument doc = 
					(javax.swing.text.html.HTMLDocument) kit.createDefaultDocument();

				editor.read(ResourceLocator.getInstance().getFileAsInputStream("rulesOfEngagement.html"),doc);
	
				
		} catch (Exception e) {this.setTitle(e.toString());}
		
		//scoreTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//		ResourceLocator rl = ResourceLocator.getInstance();
//		Image icon = rl.getImage("icon.gif");
//		this.setIconImage(icon);
		JLayeredPane layeredPane = new JLayeredPane();		
		setContentPane(layeredPane);
		setBackground(Color.GREEN);
		launchFrame(this);
		drawHolders();
	}

	private void initScores() {
		scores = new HighScore();
		String player = "test"; //System.getProperty("user.name");
		scores.setClient(player);
		System.out.println(player);		
		scores.addObserver(this);		
		((JMenuItem)this.getJMenuBar().getMenu(0).getMenuComponent(4)).setEnabled(scores.isConnected());
		if (!scores.isConnected())
			((JMenuItem)this.getJMenuBar().getMenu(0).getMenuComponent(4)).setToolTipText("Server Down");
		if (scores.isConnected()) scores.loadFromServer();
		showWelcomeMsg();
	}
	
	private void initGame(Game game) {
		wrapModel(game);
//		holders = model.getHolders();
		makeDriver();		
		model.startTimer();		
	}
	
	private void showWelcomeMsg() {
		if (!scores.isConnected())
			JOptionPane.showMessageDialog(this, "Won't be able to persist your results.", 
				"Error: The HighScoreServer is Down!", JOptionPane.INFORMATION_MESSAGE);
	}

	public void newGame() {
		scores.addGame(model.getPlayer(), model.getDuration(), model.getScore());
		restartGame();
	}
	
	private void restartGame() {
		model.delete();
		System.gc();
		this.repaint();
		initGame(new Game());
	}
	
	private void wrapModel(Game game) {
		model = new Wrapper(game, this);
		model.addObserver(this);
		//must be done AFTER the creation of the model; first set the client then load!
	}
	
	private void makeDriver() {
		if (driver!=null) {
			getContentPane().removeMouseListener(driver);
			getContentPane().removeMouseMotionListener(driver);
		}
		driver = Driver.getInstanceOf(this, model);
		getContentPane().addMouseListener(driver);
		getContentPane().addMouseMotionListener(driver);
	}
	

	
	private void drawHolders() {
		JLabel col1 = new JLabel();
		JLabel col2 = new JLabel();
		JLabel col3 = new JLabel();
		JLabel col4 = new JLabel();
		JLabel col5 = new JLabel();
		JLabel col6 = new JLabel();
		JLabel col7 = new JLabel();
		JLabel col8 = new JLabel();
		
		JLabel fc1 = new JLabel();
		JLabel fc2 = new JLabel();
		JLabel fc3 = new JLabel();
		JLabel fc4 = new JLabel();
		
		JLabel ec1 = new JLabel();
		JLabel ec2 = new JLabel();
		JLabel ec3 = new JLabel();
		JLabel ec4 = new JLabel();
		
//		col1.setBorder(BorderFactory.createLineBorder(Color.black)); //COLUMN_Y_OFFSET
		col1.setBounds(1+COLUMN_X_OFFSET+0*(CARD_WIDTH+COLUMN_X_OFFSET), COLUMN_Y_OFFSET+COLUMN_Y_STEP, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(col1, new Integer(-1));		
//		col2.setBorder(BorderFactory.createLineBorder(Color.black)); 
		col2.setBounds(1+COLUMN_X_OFFSET+1*(CARD_WIDTH+COLUMN_X_OFFSET), COLUMN_Y_OFFSET+COLUMN_Y_STEP, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(col2, new Integer(-1));	
//		col3.setBorder(BorderFactory.createLineBorder(Color.black)); 
		col3.setBounds(1+COLUMN_X_OFFSET+2*(CARD_WIDTH+COLUMN_X_OFFSET), COLUMN_Y_OFFSET+COLUMN_Y_STEP, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(col3, new Integer(-1));		
//		col4.setBorder(BorderFactory.createLineBorder(Color.black)); 
		col4.setBounds(1+COLUMN_X_OFFSET+3*(CARD_WIDTH+COLUMN_X_OFFSET), COLUMN_Y_OFFSET+COLUMN_Y_STEP, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(col4, new Integer(-1));		
//		col5.setBorder(BorderFactory.createLineBorder(Color.black)); 
		col5.setBounds(1+COLUMN_X_OFFSET+4*(CARD_WIDTH+COLUMN_X_OFFSET), COLUMN_Y_OFFSET+COLUMN_Y_STEP, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(col5, new Integer(-1));		
//		col6.setBorder(BorderFactory.createLineBorder(Color.black)); 
		col6.setBounds(1+COLUMN_X_OFFSET+5*(CARD_WIDTH+COLUMN_X_OFFSET), COLUMN_Y_OFFSET+COLUMN_Y_STEP, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(col6, new Integer(-1));		
//		col7.setBorder(BorderFactory.createLineBorder(Color.black)); 
		col7.setBounds(1+COLUMN_X_OFFSET+6*(CARD_WIDTH+COLUMN_X_OFFSET), COLUMN_Y_OFFSET+COLUMN_Y_STEP, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(col7, new Integer(-1));		
//		col8.setBorder(BorderFactory.createLineBorder(Color.black)); 
		col8.setBounds(1+COLUMN_X_OFFSET+7*(CARD_WIDTH+COLUMN_X_OFFSET), COLUMN_Y_OFFSET+COLUMN_Y_STEP, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(col8, new Integer(-1));
		
//		fc1.setBorder(BorderFactory.createLineBorder(Color.black)); 
		fc1.setBounds(1+CELL_X_OFFSET+0*(CARD_WIDTH+CELL_X_OFFSET), CELL_Y_OFFSET, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(fc1, new Integer(-1));
//		fc2.setBorder(BorderFactory.createLineBorder(Color.black)); 
		fc2.setBounds(1+CELL_X_OFFSET+1*(CARD_WIDTH+CELL_X_OFFSET), CELL_Y_OFFSET, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(fc2, new Integer(-1));
//		fc3.setBorder(BorderFactory.createLineBorder(Color.black)); 
		fc3.setBounds(1+CELL_X_OFFSET+2*(CARD_WIDTH+CELL_X_OFFSET), CELL_Y_OFFSET, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(fc3, new Integer(-1));
//		fc4.setBorder(BorderFactory.createLineBorder(Color.black)); 
		fc4.setBounds(1+CELL_X_OFFSET+3*(CARD_WIDTH+CELL_X_OFFSET), CELL_Y_OFFSET, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(fc4, new Integer(-1));
		
		
//		ec1.setBorder(BorderFactory.createLineBorder(Color.black)); 
		ec1.setBounds(1+END_CELL_X_STEP+CELL_X_OFFSET+0*(CARD_WIDTH+CELL_X_OFFSET), CELL_Y_OFFSET, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(ec1, new Integer(-1));
//		ec2.setBorder(BorderFactory.createLineBorder(Color.black)); 
		ec2.setBounds(1+END_CELL_X_STEP+CELL_X_OFFSET+1*(CARD_WIDTH+CELL_X_OFFSET), CELL_Y_OFFSET, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(ec2, new Integer(-1));
//		ec3.setBorder(BorderFactory.createLineBorder(Color.black)); 
		ec3.setBounds(1+END_CELL_X_STEP+CELL_X_OFFSET+2*(CARD_WIDTH+CELL_X_OFFSET), CELL_Y_OFFSET, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(ec3, new Integer(-1));
//		ec4.setBorder(BorderFactory.createLineBorder(Color.black)); 
		ec4.setBounds(1+END_CELL_X_STEP+CELL_X_OFFSET+3*(CARD_WIDTH+CELL_X_OFFSET), CELL_Y_OFFSET, CARD_WIDTH-2, CARD_HEIGHT);
		getContentPane().add(ec4, new Integer(-1));
		
		fc1.setText("FreeCell");
		fc2.setText("FreeCell");
		fc3.setText("FreeCell");
		fc4.setText("FreeCell");
		
		ec1.setText("Spade");
		ec2.setText("Diamond");
		ec3.setText("Heart");
		ec4.setText("Club");
		
		ResourceLocator rl = ResourceLocator.getInstance();
		ImageIcon fcIcon = rl.getIcon(fc1.getText());
		ImageIcon ec1Icon = rl.getIcon(ec1.getText());
		ImageIcon ec2Icon = rl.getIcon(ec2.getText());
		ImageIcon ec3Icon = rl.getIcon(ec3.getText());
		ImageIcon ec4Icon = rl.getIcon(ec4.getText());
		
		fc1.setIcon(fcIcon);
		fc2.setIcon(fcIcon);
		fc3.setIcon(fcIcon);
		fc4.setIcon(fcIcon);
		ec1.setIcon(ec1Icon);
		ec2.setIcon(ec2Icon);
		ec3.setIcon(ec3Icon);
		ec4.setIcon(ec4Icon);
		
		col1.setIcon(fcIcon);
		col2.setIcon(fcIcon);
		col3.setIcon(fcIcon);
		col4.setIcon(fcIcon);
		col5.setIcon(fcIcon);
		col6.setIcon(fcIcon);
		col7.setIcon(fcIcon);
		col8.setIcon(fcIcon);
		
	}
	
    public void loadScores() {
    	String[] names = {"Player", "Duration", "Score"};
    	scoreTableModel.setDataVector(scores.getTableModel(), names);    	
    }
        
	
	
	
//	public List<IHolder> getHolders() {
//		return holders;
//	}
	
	private void launchFrame(JFrame window) {
		window.pack();
		Dimension dim = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
		window.setLocation(dim.width/6-window.getWidth()/5,
				dim.height/6-window.getHeight()/5);
		window.setSize(new Dimension(2*COLUMN_X_OFFSET+8*(CARD_WIDTH+COLUMN_X_OFFSET),700));	
		window.setMaximizedBounds(
				new Rectangle(2*COLUMN_X_OFFSET+8*(CARD_WIDTH+COLUMN_X_OFFSET), dim.height));
		window.setMaximumSize(new Dimension(2*COLUMN_X_OFFSET+8*(CARD_WIDTH+COLUMN_X_OFFSET), dim.height));
		window.setVisible(true);
		
	}
	
	public void update(Observable o, Object arg) {
		if (o.equals(scores)) loadScores();
		if (o.equals(model)) {
			if (model.hasWon()) {
				scores.addGame(model.getPlayer(), model.getDuration(), model.getScore());
				JOptionPane.showMessageDialog(this, "Score: "+model.getScore()+
						" Time: "+Wrapper.getStringDuration(model.getDuration()), 
						"Congratulations "+model.getPlayer()+", You Won!", JOptionPane.INFORMATION_MESSAGE);
				restartGame();
			}	else	{driver.update(o);}
		} 
	}


}
